home *** CD-ROM | disk | FTP | other *** search
/ Aminet 20 / Aminet 20 (1997)(GTI - Schatztruhe)[!][Aug 1997].iso / Aminet / comm / www / HTP.lha / HTP / source / html.c < prev    next >
C/C++ Source or Header  |  1997-06-21  |  15KB  |  617 lines

  1. /*
  2. //
  3. // html.c
  4. //
  5. // HTML markup tag functions
  6. //
  7. // Copyright (c) 1995-96 Jim Nelson.  Permission to distribute
  8. // granted by the author.  No warranties are made on the fitness of this
  9. // source code.
  10. // Amiga version - 1997 - Geert Bevin
  11. //
  12. */
  13.  
  14. #include "htp.h"
  15.  
  16. char *FindWhitespace(char *str)
  17. {
  18.     assert(str != NULL);
  19.  
  20.     while(*str != NUL)
  21.     {
  22.         if(isspace(*str))
  23.         {
  24.             break;
  25.         }
  26.         str++;
  27.     }
  28.  
  29.     return str;
  30. }
  31.  
  32. char *FindNonWhitespace(char *str)
  33. {
  34.     assert(str != NULL);
  35.  
  36.     while(*str != NUL)
  37.     {
  38.         if(!isspace(*str))
  39.         {
  40.             break;
  41.         }
  42.         str++;
  43.     }
  44.  
  45.     return str;
  46. }   
  47.  
  48. /*
  49. // HTML_ATTRIBUTE functions
  50. */
  51.  
  52. BOOL MakeAttribute(HTML_ATTRIBUTE *htmlAttribute, const char *name,
  53.     const char *value, BOOL quoted)
  54. {
  55.     assert(htmlAttribute != NULL);
  56.     assert(name != NULL);
  57.  
  58.     /* create a duplicate of the string for the attribute structure */
  59.     if((htmlAttribute->name = DuplicateString(name)) == NULL)
  60.     {
  61.         return FALSE;
  62.     }
  63.  
  64.     /* do the same for the value, if it exists */
  65.     if(value != NULL)
  66.     {
  67.         if((htmlAttribute->value = DuplicateString(value)) == NULL)
  68.         {
  69.             FreeMemory(htmlAttribute->name);
  70.             htmlAttribute->name = NULL;
  71.             return FALSE;
  72.         }
  73.     }
  74.     else
  75.     {
  76.         htmlAttribute->value = NULL;
  77.     }
  78.  
  79.     /* keep track if this was a quoted value */
  80.     htmlAttribute->quoted = quoted;
  81.  
  82.     return TRUE;
  83. }   
  84.  
  85. BOOL ChangeAttributeName(HTML_ATTRIBUTE *htmlAttribute, const char *name)
  86. {
  87.     assert(htmlAttribute != NULL);
  88.  
  89.     /* although name should never be null, let it slide */
  90.     if(htmlAttribute->name != NULL)
  91.     {
  92.         FreeMemory(htmlAttribute->name);
  93.         htmlAttribute->name = NULL;
  94.     }
  95.  
  96.     if((htmlAttribute->name = DuplicateString(name)) == NULL)
  97.     {
  98.         return FALSE;
  99.     }
  100.  
  101.     return TRUE;
  102. }
  103.  
  104. BOOL ChangeAttributeValue(HTML_ATTRIBUTE *htmlAttribute, const char *value,
  105.     BOOL quoted)
  106. {
  107.     assert(htmlAttribute != NULL);
  108.  
  109.     /* free the value's memory, if previously defined */
  110.     if(htmlAttribute->value != NULL)
  111.     {
  112.         FreeMemory(htmlAttribute->value);
  113.         htmlAttribute->value = NULL;
  114.     }
  115.  
  116.     /* if the new value is defined, allocate room and copy it in */
  117.     if(value != NULL)
  118.     {
  119.         if((htmlAttribute->value = DuplicateString(value)) == NULL)
  120.         {
  121.             return FALSE;
  122.         }
  123.     }
  124.  
  125.     htmlAttribute->quoted = quoted;
  126.  
  127.     return TRUE;
  128. }   
  129.  
  130. void DestroyAttribute(HTML_ATTRIBUTE *htmlAttribute)
  131. {
  132.     assert(htmlAttribute != NULL);
  133.     /* the attribute should always have a name */
  134.     assert(htmlAttribute->name != NULL);
  135.  
  136.     FreeMemory(htmlAttribute->name);
  137.     htmlAttribute->name = NULL;
  138.  
  139.     if(htmlAttribute->value != NULL)
  140.     {
  141.         FreeMemory(htmlAttribute->value);
  142.         htmlAttribute->value = NULL;
  143.     }
  144. }   
  145.  
  146. /*
  147. // HTML_MARKUP functions
  148. */
  149.  
  150. /*
  151.     this is perhaps the ugliest piece of code in the entire program ... it
  152.     is also one of the most critical.  (Surprise.)
  153.  
  154.     Allan Todd provided a very important fix: htp 1.0 and before would
  155.     crash and burn if it hit a large comment.  This was problematic for
  156.     JavaScript and VBScript, which embed the interpreted code in comments
  157.     to prevent other browsers from gagging.  Allans solution is simply
  158.     to pack the entire comment into one attribute.
  159. */
  160. BOOL PlaintextToMarkup(const char *plaintext, HTML_MARKUP *htmlMarkup)
  161. {
  162.     char *plainBuffer;
  163.     char *plainPtr;
  164.     BOOL valueFound;
  165.     BOOL quotedValue;
  166.     BOOL endOfMarkup;
  167.     char *token;
  168.     char *value;
  169.     BOOL isComment;
  170.  
  171.     assert(plaintext != NULL);
  172.     assert(htmlMarkup != NULL);
  173.  
  174.     /* although this isnt a good thing, its not something to halt execution over */
  175.     if(plaintext[0] == NUL)
  176.     {
  177.         DEBUG_PRINT(("no plaintext to convert"));
  178.         return FALSE;
  179.     }
  180.  
  181.     /* allocate and copy the markup field into the structure */
  182.     if((plainBuffer = DuplicateString(plaintext)) == NULL)
  183.     {
  184.         DEBUG_PRINT(("unable to duplicate plaintext string"));
  185.         return FALSE;
  186.     }
  187.     plainPtr = plainBuffer;
  188.  
  189.     /* initialize the markup structure */
  190.     htmlMarkup->tag = NULL;
  191.     htmlMarkup->attribCount = 0;
  192.  
  193.     /* walk the markup and build tag and attribute list (re-using the markup */
  194.     /* argument to walk the copied string) */
  195.  
  196.     /* walk past any initial whitespace */
  197.     plainPtr = FindNonWhitespace(plainPtr);
  198.     if(*plainPtr == NUL)
  199.     {
  200.         FreeMemory(plainBuffer);
  201.         return TRUE;
  202.     }
  203.  
  204.     /* mark first token as the tag */
  205.     token = plainPtr;
  206.  
  207.     /* check if this is a comment */
  208.     isComment = (strncmp(token, "!--", 3) != 0) ? FALSE : TRUE;
  209.  
  210.     endOfMarkup = FALSE;
  211.  
  212.     /* walk to the first whitespace, mark it as NUL, and this is the tag */
  213.     plainPtr = FindWhitespace(plainPtr);
  214.     if(*plainPtr == NUL)
  215.     {
  216.         endOfMarkup = TRUE;
  217.     }
  218.  
  219.     /* copy the markup tag into the structure */
  220.     *plainPtr = NUL;
  221.     if((htmlMarkup->tag = DuplicateString(token)) == NULL)
  222.     {
  223.         DEBUG_PRINT(("unable to duplicate markup token"));
  224.         FreeMemory(plainBuffer);
  225.         return FALSE;
  226.     }
  227.  
  228.     if(endOfMarkup)
  229.     {
  230.         FreeMemory(plainBuffer);
  231.         return TRUE;
  232.     }
  233.  
  234.     /* advance past NUL */
  235.     plainPtr++;
  236.  
  237.     /* start walking the rest of markup, looking for attributes and their */
  238.     /* values */
  239.     while(*plainPtr != NUL)
  240.     {
  241.         /* walk past whitespace */
  242.         plainPtr = FindNonWhitespace(plainPtr);
  243.  
  244.         /* if a comment, put the whole she-bang into a single attribute */
  245.         /* and skeedaddle */
  246.         if(isComment == TRUE)
  247.         {
  248.             if(AddAttributeToMarkup(htmlMarkup, plainPtr, FALSE, FALSE) == TRUE)
  249.             {
  250.                 FreeMemory(plainBuffer);
  251.                 return TRUE;
  252.             }
  253.  
  254.             /* couldnt add it for some reason */
  255.             DEBUG_PRINT(("unable to add comment to markup"));
  256.             DestroyMarkupStruct(htmlMarkup);
  257.             FreeMemory(plainBuffer);
  258.  
  259.             return FALSE;
  260.         }
  261.  
  262.         /* if not NUL, then hit an attribute */
  263.         if(*plainPtr != NUL)
  264.         {
  265.             /* mark the beginning of the attribute */
  266.             token = plainPtr;
  267.             value = NULL;
  268.             quotedValue = FALSE;
  269.  
  270.             /* walk through the attribute, looking for whitespace or an */
  271.             /* equal sign */
  272.             valueFound = FALSE;
  273.             while(*plainPtr != NUL)
  274.             {
  275.                 if(*plainPtr == '=')
  276.                 {
  277.                     valueFound = TRUE;
  278.                     break;
  279.                 }
  280.                 else if(isspace(*plainPtr))
  281.                 {
  282.                     /* end of attribute */
  283.                     break;
  284.                 }
  285.                 plainPtr++;
  286.             }
  287.  
  288.             if(*plainPtr != NUL)
  289.             {
  290.                 /* mark as NUL to delimit the attribute name */
  291.                 *plainPtr = NUL;
  292.                 plainPtr++;
  293.  
  294.                 /* skip past whitespace (looking for a value) */
  295.                 plainPtr = FindNonWhitespace(plainPtr);
  296.  
  297.                 /* is this an attribute or value for previous attribute? */
  298.                 if(*plainPtr != NUL)
  299.                 {
  300.                     if(valueFound)
  301.                     {
  302.                         if(*plainPtr == '\"')
  303.                         {
  304.                             /* quoted value, search for end quote */
  305.                             quotedValue = TRUE;
  306.                             plainPtr++;
  307.                         }
  308.                         else
  309.                         {
  310.                             quotedValue = FALSE;
  311.                         }
  312.  
  313.                         /* mark the beginning of the value */
  314.                         if(*plainPtr != NUL)
  315.                         {
  316.                             value = plainPtr;
  317.                         }
  318.  
  319.                         /* find the end of the value */
  320.                         while(*plainPtr != NUL)
  321.                         {
  322.                             if(isspace(*plainPtr))
  323.                             {
  324.                                 if(quotedValue == FALSE)
  325.                                 {
  326.                                     break;
  327.                                 }
  328.                             }
  329.  
  330.                             if((*plainPtr == '\"') && (quotedValue))
  331.                             {
  332.                                 break;
  333.                             }
  334.  
  335.                             plainPtr++;
  336.                         }
  337.  
  338.                         /* mark the end of the value */
  339.                         if(*plainPtr != NUL)
  340.                         {
  341.                             *plainPtr = NUL;
  342.                             plainPtr++;
  343.                         }
  344.                     }
  345.                 }
  346.             }
  347.  
  348.             /* add the new attribute to the markup structure */
  349.             if(AddAttributeToMarkup(htmlMarkup, token, value, quotedValue) == FALSE)
  350.             {
  351.                 DEBUG_PRINT(("unable to add attribute to markup"));
  352.                 DestroyMarkupStruct(htmlMarkup);
  353.                 FreeMemory(plainBuffer);
  354.                 return FALSE;
  355.             }
  356.         }
  357.     }
  358.  
  359.     FreeMemory(plainBuffer);
  360.  
  361.     return TRUE;
  362. }   
  363.  
  364. BOOL AddAttributeToMarkup(HTML_MARKUP *htmlMarkup, const char *name,
  365.     const char *value, BOOL quotedValue)
  366. {
  367.     assert(htmlMarkup != NULL);
  368.     assert(name != NULL);
  369.  
  370.     if(htmlMarkup->attribCount < MAX_ATTRIBUTE_COUNT)
  371.     {
  372.         if(MakeAttribute(&htmlMarkup->attrib[htmlMarkup->attribCount], name,
  373.             value, quotedValue) == TRUE)
  374.         {
  375.             htmlMarkup->attribCount++;
  376.             return TRUE;
  377.         }
  378.         else
  379.         {
  380.             DEBUG_PRINT(("unable to make attribute name=\"%s\" value=\"%s\"",
  381.                 name, value));
  382.         }
  383.     }
  384.     else
  385.     {
  386.         DEBUG_PRINT(("markup structure full!  tag=\"%s\" name=\"%s\" value=\"%s\"",
  387.             htmlMarkup->tag, name, value));
  388.     }
  389.  
  390.     return FALSE;
  391. }   
  392.  
  393. void DestroyMarkupStruct(HTML_MARKUP *htmlMarkup)
  394. {
  395.     uint ctr;
  396.  
  397.     assert(htmlMarkup != NULL);
  398.  
  399.     /* destroy the tag */
  400.     /* do not assert against this, as this function might be used to */
  401.     /* destroy a partially-built structure */
  402.     if(htmlMarkup->tag != NULL)
  403.     {
  404.         FreeMemory(htmlMarkup->tag);
  405.         htmlMarkup->tag = NULL;
  406.     }
  407.  
  408.     /* destroy all markup attributes */
  409.     for(ctr = 0; ctr < htmlMarkup->attribCount; ctr++)
  410.     {
  411.         DestroyAttribute(&htmlMarkup->attrib[ctr]);
  412.     }
  413. }   
  414.  
  415. BOOL IsMarkupTag(HTML_MARKUP *htmlMarkup, const char *tag)
  416. {
  417.     assert(htmlMarkup != NULL);
  418.     assert(tag != NULL);
  419.  
  420.     return (stricmp(htmlMarkup->tag, tag) == 0) ? TRUE : FALSE;
  421. }   
  422.  
  423. static uint MarkupAttributeIndex(HTML_MARKUP *htmlMarkup, const char *name)
  424. {
  425.     uint ctr;
  426.  
  427.     assert(htmlMarkup != NULL);
  428.     assert(name != NULL);
  429.  
  430.     for(ctr = 0; ctr < htmlMarkup->attribCount; ctr++)
  431.     {
  432.         assert(htmlMarkup->attrib[ctr].name != NULL);
  433.  
  434.         if(stricmp(htmlMarkup->attrib[ctr].name, name) == 0)
  435.         {
  436.             return ctr;
  437.         }
  438.     }
  439.  
  440.     return ERROR;
  441. }   
  442.  
  443. BOOL MarkupToPlaintext(HTML_MARKUP *htmlMarkup, char **plaintext)
  444. {
  445.     uint ctr;
  446.     HTML_ATTRIBUTE *htmlAttribute;
  447.     uint size;
  448.     uint attrSize;
  449.     uint maxAttrSize;
  450.     char *buffer;
  451.     char *attrBuffer;
  452.  
  453.     assert(htmlMarkup != NULL);
  454.     assert(htmlMarkup->tag != NULL);
  455.     assert(plaintext != NULL);
  456.  
  457.     /* estimate the required size of the plaintext buffer */
  458.  
  459.     maxAttrSize = 0;
  460.     attrBuffer = NULL;
  461.  
  462.     /* additional byte is to account for NUL */
  463.     size = strlen(htmlMarkup->tag) + 1;
  464.     for(ctr = 0; ctr < htmlMarkup->attribCount; ctr++)
  465.     {
  466.         htmlAttribute = &htmlMarkup->attrib[ctr];
  467.  
  468.         assert(htmlAttribute != NULL);
  469.         assert(htmlAttribute->name != NULL);
  470.  
  471.         /* an additional byte is added to size for preceding space char */
  472.         attrSize = strlen(htmlAttribute->name) + 1;
  473.  
  474.         if(htmlAttribute->value != NULL)
  475.         {
  476.             /* additional byte added to account for equal sign */
  477.             attrSize += strlen(htmlAttribute->value) + 1;
  478.  
  479.             if(htmlAttribute->quoted)
  480.             {
  481.                 /* account for the quote characters */
  482.                 attrSize += 2;
  483.             }
  484.         }
  485.  
  486.         /* additional byte added for NULL character */
  487.         attrSize++;
  488.  
  489.         size += attrSize;
  490.         if(maxAttrSize < attrSize)
  491.         {
  492.             maxAttrSize = attrSize;
  493.         }
  494.     }
  495.  
  496.     if((buffer = AllocMemory(size)) == NULL)
  497.     {
  498.         DEBUG_PRINT(("unable to allocate plaintext buffer (%u bytes)", size));
  499.         return FALSE;
  500.     }
  501.  
  502.     if(maxAttrSize != 0)
  503.     {
  504.         if((attrBuffer = AllocMemory(maxAttrSize)) == NULL)
  505.         {
  506.             DEBUG_PRINT(("unable to allocate attribute plaintext buffer (%u bytes)",
  507.                 maxAttrSize));
  508.             FreeMemory(buffer);
  509.             return FALSE;
  510.         }
  511.     }
  512.     else
  513.     {
  514.         attrBuffer = NULL;
  515.     }
  516.  
  517.     /* start copying in the markup as plaintext */
  518.     strcpy(buffer, htmlMarkup->tag);
  519.  
  520.     for(ctr = 0; ctr < htmlMarkup->attribCount; ctr++)
  521.     {
  522.         htmlAttribute = &htmlMarkup->attrib[ctr];
  523.  
  524.         /* checked previously, but check again */
  525.         assert(htmlAttribute != NULL);
  526.         assert(htmlAttribute->name != NULL);
  527.  
  528.         /* this had best be true */
  529.         assert(attrBuffer != NULL);
  530.  
  531.         /* its a little ugly, but is much quicker than prior tactic */
  532.         /* (an equally ugly set of strcat() functions used conditionally) */
  533.         if(htmlAttribute->value == NULL)
  534.         {
  535.             sprintf(attrBuffer, " %s", htmlAttribute->name);
  536.         }
  537.         else
  538.         {
  539.             if(htmlAttribute->quoted == FALSE)
  540.             {
  541.                 sprintf(attrBuffer, " %s=%s", htmlAttribute->name,
  542.                     htmlAttribute->value);
  543.             }
  544.             else
  545.             {
  546.                 sprintf(attrBuffer, " %s=\"%s\"", htmlAttribute->name,
  547.                     htmlAttribute->value);
  548.             }
  549.         }
  550.  
  551.         /* copy in the attribute plaintext into the markup plaintext */
  552.         strcat(buffer, attrBuffer);
  553.     }
  554.  
  555.     /* free the attribute buffer */
  556.     FreeMemory(attrBuffer);
  557.  
  558.     /* give the buffer to caller */
  559.     *plaintext = buffer;
  560.  
  561.     return TRUE;
  562. }   
  563.  
  564. BOOL IsAttributeInMarkup(HTML_MARKUP *htmlMarkup, const char *name)
  565. {
  566.     assert(htmlMarkup != NULL);
  567.  
  568.     return (MarkupAttributeIndex(htmlMarkup, name) != ERROR) ? TRUE : FALSE;
  569. }   
  570.  
  571. const char *MarkupAttributeValue(HTML_MARKUP *htmlMarkup, const char *name)
  572. {
  573.     uint index;
  574.  
  575.     assert(htmlMarkup != NULL);
  576.  
  577.     if((index = MarkupAttributeIndex(htmlMarkup, name)) == ERROR)
  578.     {
  579.         return NULL;
  580.     }
  581.  
  582.     /* check validity of attribute */
  583.     assert(htmlMarkup->attrib[index].name != NULL);
  584.  
  585.     return htmlMarkup->attrib[index].value;
  586. }   
  587.  
  588. BOOL ChangeMarkupTag(HTML_MARKUP *htmlMarkup, const char *tag)
  589. {
  590.     assert(htmlMarkup != NULL);
  591.     assert(tag != NULL);
  592.  
  593.     if(htmlMarkup->tag != NULL)
  594.     {
  595.         FreeMemory(htmlMarkup->tag);
  596.     }
  597.  
  598.     htmlMarkup->tag = DuplicateString(tag);
  599.  
  600.     return (htmlMarkup->tag != NULL) ? TRUE : FALSE;
  601. }
  602.  
  603. const HTML_ATTRIBUTE *MarkupAttribute(HTML_MARKUP *htmlMarkup, uint index)
  604. {
  605.     assert(htmlMarkup != NULL);
  606.  
  607.     if(index >= htmlMarkup->attribCount)
  608.     {
  609.         return NULL;
  610.     }
  611.  
  612.     assert(htmlMarkup->attribCount < MAX_ATTRIBUTE_COUNT);
  613.  
  614.     return &htmlMarkup->attrib[index];
  615. }
  616.  
  617.